package cn.lingyangwl.agile.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.lingyangwl.agile.common.core.exception.enums.*;
import cn.lingyangwl.agile.infra.*;
import cn.lingyangwl.agile.infra.module.group.model.rqrs.*;
import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.model.enums.*;
import cn.lingyangwl.agile.system.assembly.*;
import cn.lingyangwl.agile.system.mapper.*;
import cn.lingyangwl.agile.system.model.entity.*;
import cn.lingyangwl.agile.system.model.rqrs.menu.*;
import cn.lingyangwl.agile.system.service.*;
import cn.lingyangwl.agile.tenant.core.*;
import cn.lingyangwl.framework.data.mate.annotations.*;
import cn.lingyangwl.framework.tool.core.*;
import cn.lingyangwl.framework.tool.core.exception.*;
import cn.lingyangwl.framework.validation.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 移动端菜单
 *
 * @author shenguangyang
 */
@Slf4j
@Service
public class MobileMenuServiceImpl extends ServiceImpl<MobileMenuMapper, MobileMenu>
    implements IService<MobileMenu>, MobileMenuService {

    @Resource
    private MobileMenuAssembly mobileMenuAssembly;
    @Resource
    private InfraApi infraApi;
    @Resource
    private Validator validator;

    @Override
    @FieldBindHandle
    @Tenant(level = DataIsolateLevel.MGT)
    public List<MobileMenuResp> listMobileMenu(MobileMenuListReq req) {
        LambdaQueryWrapper<MobileMenu> lqw = MobileMenu.lqw()
            .like(StringUtils.isNotEmpty(req.getTitle()), MobileMenu::getTitle, req.getTitle())
            .eq(StringUtils.isNotEmpty(req.getDisplayPosition()), MobileMenu::getDisplayPosition, req.getDisplayPosition())
            .orderByAsc(MobileMenu::getSortNo);

        List<MobileMenu> list = this.list(lqw);
        List<String> groupCodes = list.stream().map(MobileMenu::getGroupCode).filter(StringUtils::isNotEmpty)
            .collect(Collectors.toList());
        groupCodes.add("-1");

        DataGroupQuery queryGroupReq = new DataGroupQuery().setBizType(DataGroupBizTypeEnum.MOBILE_MENU.getType())
            .setCodeList(groupCodes);
        Map<String, String> groupMap = infraApi.listDataGroup(queryGroupReq).stream().collect(
            Collectors.groupingBy(DataGroupBase::getCode, Collectors.mapping(DataGroupBase::getName, Collectors.joining())));

        return list.stream()
    	        .map(e -> {
                    MobileMenuResp resp = mobileMenuAssembly.toMobileMenuResp(e);
                    resp.setGroupName(groupMap.get(e.getGroupCode()));
                    return resp;
                }).collect(Collectors.toList());
    }

    @Override
    @Tenant(level = DataIsolateLevel.MGT)
    public List<MobileMenuTreeResp> listMobileMenuTree(MobileMenuListReq req) {
        List<MobileMenuTreeResp> respList = new ArrayList<>();
        List<MobileMenuResp> list = listMobileMenu(req);
        Map<String, List<MobileMenuResp>> map = list.stream().collect(Collectors.groupingBy(e -> e.getGroupCode() + ":" + e.getGroupName()));
        map.forEach((k, v) -> {
            MobileMenuTreeResp resp = new MobileMenuTreeResp();
            resp.setGroupCode(k.split(":")[0]);
            resp.setGroupName(k.split(":")[1]);
            resp.setMenuList(v);
            respList.add(resp);
        });
        return respList;
    }

    @Override
    @FieldBindHandle
    public MobileMenuResp getMobileMenu(Long id) {
        MobileMenu entity = this.getById(id);
        if (Objects.isNull(entity)) {
            return null;
        }
        MobileMenuResp resp = mobileMenuAssembly.toMobileMenuResp(entity);
        DataGroupQuery queryGroupReq = new DataGroupQuery()
            .setBizType(DataGroupBizTypeEnum.MOBILE_MENU.getType())
            .setCode(StringUtils.firstNonEmpty(entity.getGroupCode(), "no"));
        Map<String, String> groupMap = infraApi.listDataGroup(queryGroupReq).stream().collect(
            Collectors.groupingBy(DataGroupBase::getCode, Collectors.mapping(DataGroupBase::getName, Collectors.joining())));

        resp.setGroupName(groupMap.get(entity.getGroupCode()));
        return resp;
    }

    @Override
    public boolean saveMobileMenu(MobileMenuSaveReq req) {
        MobileMenu entity = mobileMenuAssembly.toMobileMenu(req);
    	return this.save(entity);
    }

    @Override
    public boolean updateMobileMenu(MobileMenuUpdateReq req) {
        MobileMenu entity = mobileMenuAssembly.toMobileMenu(req);
    	return this.updateById(entity);
    }

    @Override
    public boolean deleteMobileMenu(Long id) {
    	return this.removeById(id);
    }
    
    @Override
    public boolean batchDeleteMobileMenu(List<Long> ids) {
    	return this.removeByIds(ids);
    }

    @Override
    public boolean deleteGroup(DataGroupDeleteReq req) {
        DataGroupQuery listReq = new DataGroupQuery()
            .setIds(req.getIds()).setBizType(req.getBizType());
        List<String> groupCodes = infraApi.listDataGroup(listReq).stream()
            .map(DataGroupBase::getCode).collect(Collectors.toList());
        if (CollUtil.isEmpty(groupCodes)) {
            return true;
        }
        LambdaQueryWrapper<MobileMenu> lqw = MobileMenu.lqw().in(MobileMenu::getGroupCode, groupCodes);
        if (this.count(lqw) > 0) {
            throw new BizException(GlobalErrorEnum.DATA_GROUP_USED);
        }

        DataGroupDeleteReq deleteReq = new DataGroupDeleteReq();
        deleteReq.setBizType(DataGroupBizTypeEnum.MOBILE_MENU.getType()).setIds(req.getIds());
        infraApi.batchDeleteDataGroup(deleteReq);
        return infraApi.batchDeleteDataGroup(deleteReq);
    }

    @Override
    public Long saveGroup(DataGroupSaveReq req) {
        ValidationUtils.validate(validator, req);
        DataGroupBizTypeEnum.checkExistByType(req.getBizType());
        return infraApi.saveDataGroup(req);
    }

    @Override
    public boolean updateGroup(DataGroupUpdateReq req) {
        ValidationUtils.validate(validator, req);
        return infraApi.updateDataGroup(req);
    }
}
